package com.yunji.system.config.mybatis;

import com.yunji.common.model.dto.LoginInfo;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.system.service.TokenService;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Project: yunji-coffee
 * @Package: com.yunji.framework.config.mybatis
 * @Title: MybatisInterceptor
 * @Description: 处理SQL语句公共信息
 * <p>
 * History:
 * Date                     Version     Author          Summary
 * ============================================================
 * 2024-04-17 16:04:10      V1.0        HuaAo       新建类
 */
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MybatisInterceptor implements Interceptor {
    private static final Logger logs = LoggerFactory.getLogger(MybatisInterceptor.class);

    @Resource
    private TokenService tokenService;

    // 新增参数
    private static final Map<String, Object> INSERT_FILED = new ConcurrentHashMap<>();
    // 修改参数
    private static final Map<String, Object> UPDATE_FILED = new ConcurrentHashMap<>();

    /**
     * @param command   语句指令
     * @param parameter 语句参数
     * @Title handleInsert
     * @Desc 处理插入参数信息
     * @Date 2024-04-20 09:54:34.133
     */
    private void handleInsert(SqlCommandType command, Object parameter) {
        if (SqlCommandType.INSERT != command) {
            return;
        }

        Field[] fields = BeanUtils.getFields(parameter);
        for (Field field : fields) {
            try {
                String name = field.getName();

                field.setAccessible(true);
                Object object = field.get(parameter);
                field.setAccessible(false);
                if (!INSERT_FILED.containsKey(name) || BeanUtils.isNotNull(object)) {
                    continue;
                }

                field.setAccessible(true);
                field.set(parameter, INSERT_FILED.get(name));
                field.setAccessible(false);
            } catch (Exception e) {
                logs.error("初始化参数失败", e);
            }
        }
    }

    /**
     * @param command   语句命令
     * @param parameter 语句参数
     * @Title handleUpdate
     * @Desc 处理更新语句信息
     * @Date 2024-04-20 10:09:29.205
     */
    private void handleUpdate(SqlCommandType command, Object parameter) {
        if (SqlCommandType.UPDATE != command) {
            return;
        }

        if (parameter instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap<?> p = (MapperMethod.ParamMap<?>) parameter;
            // update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q--
            String et = "et";
            parameter = p.containsKey(et) ? p.get(et) : p.get("param1");
            // update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q-

            // update-begin-author:scott date:20190729 for:更新指定字段时报错 issues/#516-
            if (parameter == null) {
                return;
            }
            // update-end-author:scott date:20190729 for:更新指定字段时报错 issues/#516-

        }

        Field[] fields = BeanUtils.getFields(parameter);

        for (Field field : fields) {
            try {
                String name = field.getName();

                if (!UPDATE_FILED.containsKey(name)) {
                    continue;
                }

                field.setAccessible(true);
                field.set(parameter, UPDATE_FILED.get(name));
                field.setAccessible(false);
            } catch (Exception e) {
                logs.error("初始化参数失败", e);
            }
        }
    }

    /**
     * @Title handleParams
     * @Desc 处理参数信息
     * @Date 2024-04-20 09:46:25.755
     */
    private void handleParams() {
        INSERT_FILED.clear();
        UPDATE_FILED.clear();
        LoginInfo user = tokenService.getUser();
        if (BeanUtils.isNull(user)) {
            return;
        }

        Long userId = user.getUserId();
        if (BeanUtils.isNotNull(userId)) {
            INSERT_FILED.put("creator", userId);
            UPDATE_FILED.put("updater", userId);
        }

        String username = user.getUsername();
        if (BeanUtils.isNotNull(username)) {
            INSERT_FILED.put("createBy", username);
            UPDATE_FILED.put("updateBy", username);
        }

        String nickName = user.getNickname();
        if (BeanUtils.isNotNull(nickName)) {
            INSERT_FILED.put("createName", nickName);
            UPDATE_FILED.put("updateName", nickName);
        }
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType command = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];
        if (parameter == null) {
            return invocation.proceed();
        }
        handleParams();

        Date d = new Date();
        INSERT_FILED.put("createTime", d);
        UPDATE_FILED.put("updateTime", d);

        handleInsert(command, parameter);

        handleUpdate(command, parameter);

        return invocation.proceed();
    }
}
